/*******************************************************************************
 * FilePath    : \Software\Examples\Ble\ble_app_peripheral_uart\Src\BSP\UART.c
 * Version     : 1.0
 * Brief       : 
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-04-03 15:06:14
 * LastEditors : AndrewHu
 * LastEditTime: 2021-04-21 10:55:20
 * Description : 
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define MAX_SIZE 200
#define AT_CMD_MAX 100
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

u32 BaudRate = BaudRate_Def;
static u8 txBuf[MAX_SIZE], rxBuf[MAX_SIZE];
static u8 txCount = 0, rxCount = 0; //待发送、接收待取出数据的Index
static u8 txLen = 0, rxLen = 0;     //已发送、接收并取出数据的Index
static u8 rxTimeOut = 0;            //接收超时，判断串口数据是否发送完成
static u8 txEn = 0;                 //发送使能标志
static u8 uartSleep = 0;            //串口进入休眠
/* Private function ----------------------------------------------------------*/
/* extern --------------------------------------------------------------------*/

/*******************************************************************************
 * Function    : UartInit
 * Brief       : 
 * Parameter   : {u32} baudRate-波特率
 * Returns     : 
 * Date        : 2020-04-03 16:53:11
 * Description : 
 ******************************************************************************/
void UartInit(u32 baudRate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    UART_InitTypeDef UART_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_0);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_0);

    UART_InitStructure.UART_BaudRate = baudRate;
    UART_InitStructure.UART_WordLength = UART_WordLength_8b;
    UART_InitStructure.UART_StopBits = UART_StopBits_1;
    UART_InitStructure.UART_Parity = UART_Parity_No;
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;

    UART_Init(UART1, &UART_InitStructure);
    UART_ITConfig(UART1, UART_IT_RXIEN, DISABLE);
    UART_ITConfig(UART1, UART_IT_TXIEN, DISABLE);
    UART_Cmd(UART1, ENABLE);

    //UART1_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //UART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_SetPriority(UART1_IRQn, (1 << __NVIC_PRIO_BITS) - 2);
}
/*******************************************************************************
 * Function    : ChangeBaudRate
 * Brief       : 更改波特率
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 16:52:30
 * Description : 
 ******************************************************************************/
void ChangeBaudRate(u32 bRate)
{
    BaudRate = bRate;
    UART_Cmd(UART1, DISABLE);
    UartInit(bRate); //初始化串口1
}
/*******************************************************************************
 * Function    : Uart2Exit
 * Brief       : 将RX脚改为外部中断脚
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-05 23:39:50
 * Description : 当芯片进入休眠时，用RX唤醒芯片
 ******************************************************************************/
void Uart2Exit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    if (uartSleep)
        return;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    UART_ITConfig(UART1, UART_IT_RXIEN, DISABLE);
    // UART_Cmd(UART1, DISABLE);
    // RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, DISABLE);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_3);
    //UART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_7);

    SYSCFG_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
    EXTI_InitStructure.EXTI_Line = EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    EXTI_ClearITPendingBit(EXTI_Line7);
    NVIC_SetPriority(EXTI4_15_IRQn, (1 << __NVIC_PRIO_BITS) - 1);

    uartSleep = 1;
}
/*******************************************************************************
 * Function    : Exit2Uart
 * Brief       : 芯片通过RX唤醒后，切换为串口通讯脚
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-05 23:40:58
 * Description :
 ******************************************************************************/
void Exit2Uart(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    u8 temp = getRunningMode();

    if (uartSleep != 1)
        return;

    if (temp == 1)
    {
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI; //48MHz
        SetRunningMode(0);                      //待机模式和低功耗模式唤醒后变为全速模式
    }
    else if (temp == 3)
    {
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI; //48MHz
        radio_resume();                         //蓝牙关闭了，重新启动
        SetRunningMode(0);                      //待机模式和低功耗模式唤醒后变为全速模式
    }
    UartInit(BaudRate);

    //SYSCFG_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
    EXTI_InitStructure.EXTI_Line = EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = DISABLE;
    EXTI_Init(&EXTI_InitStructure);

    Uart_Send_String((u8 *)"IND:Wakeup\r\n", 12);
    uartSleep = 0;
}
/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 17:06:41
 * Description : 
 ******************************************************************************/
u32 GetBaudRate(void)
{
    return BaudRate;
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UartRx_Int(void)
{
    rxBuf[rxCount] = UART_ReceiveData(UART1); //保存串口接收到的值

    //比较缓存是否溢出
    rxCount++;
    if (rxCount >= MAX_SIZE)
        rxCount = 0x00;
    rxTimeOut = 0x00; //倒计时，判断串口数据是否接收完
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UartTx_Int(void)
{
    //还有数据未发完
    if (txCount != txLen)
    {
        UART_SendData(UART1, txBuf[txLen]);
        //比较缓存是否溢出
        txLen++;
        if (txLen >= MAX_SIZE)
            txLen = 0x00;
    }
    else
    {
        //数据发送完成
        UART_ITConfig(UART1, UART_IT_TXIEN, DISABLE); //关闭串口发送中断
        txEn = 0x00;
    }
}
/*******************************************************************************
* Function   :      UART1_IRQHandler
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      串口1中断服务程序
*******************************************************************************/
void UART1_IRQHandler(void)
{
    if (UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)
    {                                                 //接收中断
        UART_ClearITPendingBit(UART1, UART_IT_RXIEN); //清串口中断
        UartRx_Int();
    }
    if (UART_GetITStatus(UART1, UART_IT_TXIEN) != RESET)
    {
        UART_ClearITPendingBit(UART1, UART_IT_TXIEN); //清发送完成中断
        UartTx_Int();
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Byte
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 18:28:52
 * Description : 串口发送一个字节
 ******************************************************************************/
void Uart_Send_Byte(u8 data)
{
    txBuf[txCount] = data;
    txCount++;
    if (txCount >= MAX_SIZE)
        txCount = 0x00;
}
/*******************************************************************************
 * Function    : Uart_Send_Byte2Ascii
 * Brief       : 
 * Parameter   : {u8} data-待发送数据
 * Returns     : 
 * Date        : 2020-03-24 18:30:09
 * Description : 串口发送一个字节（转换成ASCII）
 ******************************************************************************/
void Uart_Send_Byte2Ascii(u8 data)
{
    Uart_Send_Byte(AHL_Data_Hex2Ascii_4bit(data >> 4));
    Uart_Send_Byte(AHL_Data_Hex2Ascii_4bit(data));
}
/*******************************************************************************
 * Function    : Uart_Send_Array
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（原始数据）
 ******************************************************************************/
void Uart_Send_Array(u8 *data, u8 len)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        Uart_Send_Byte(data[i]);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array_R
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（原始数据），倒序
 ******************************************************************************/
void Uart_Send_Array_R(u8 *data, u8 len)
{
    u8 i;
    for (i = len; i != 0; i--)
    {
        Uart_Send_Byte(data[i - 1]);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array2Ascii
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-数组长度
 * Parameter   : {u8} space-是否空格做间隔
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（转成ASCII）
 ******************************************************************************/
void Uart_Send_Array2Ascii(u8 *data, u8 len, u8 space)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        Uart_Send_Byte2Ascii(data[i]);
        if (space)
            Uart_Send_Byte(' '); //插入空格
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Array2Ascii_R
 * Brief       : 
 * Parameter   : {u8*} data-待发送数组
 * Parameter   : {u8} len-待发送数组长度
 * Parameter   : {u8} space-是否空格做间隔
 * Returns     : 
 * Date        : 2020-03-24 18:30:47
 * Description : 发送一个数组（转成ASCII），倒序
 ******************************************************************************/
void Uart_Send_Array2Ascii_R(u8 *data, u8 len, u8 space)
{
    u8 i;
    for (i = len; i != 0; i--)
    {
        Uart_Send_Byte2Ascii(data[i - 1]);
        if (space)
            Uart_Send_Byte(' '); //插入空格
    }
}
/*******************************************************************************
 * Function    : Uart_Send_String
 * Brief       : 
 * Parameter   : {u8*} data-字符串或数组
 * Returns     : {u8} len-长度
 * Date        : 2020-03-24 18:48:47
 * Description : 发送一个字符串或数组
 ******************************************************************************/
void Uart_Send_String(u8 *data, u8 len)
{
    u8 i;
    for (i = 0; i < len; i++)
    {
        txBuf[txCount] = *(data + i);
        txCount++;
        if (txCount >= MAX_SIZE)
            txCount = 0x00;
    }
}
/*******************************************************************************
 * Function    : GetUartTxFlag
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-25 15:16:44
 * Description : 获取串口发送状态
 ******************************************************************************/
u8 GetUartTxFlag(void)
{
    return txEn;
}
/*******************************************************************************
 * Function    : GetUartStatus
 * Brief       : 获取串口工作状态
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-25 15:16:44
 * Description : 
 ******************************************************************************/
u8 GetUartStatus(void)
{
    if ((txEn != 0) || (txLen != txCount) || (rxLen != rxCount))
        return 1; //串口有数据待处理
    else
        return 0; //串口空闲
}
/*******************************************************************************
 * Function    : BleSendData
 * Brief       : 
 * Parameter   : {u8} overflag-串口数据是否接收完成
 * Returns     : 
 * Date        : 2020-03-23 17:36:40
 * Description : 从串口接受数组中取出数据给蓝牙发送
 ******************************************************************************/
static void BleSendData(u8 overflag)
{
    u8 i = 0;
    u8 bleUartData[20] = {0};

    if (overflag == 0)
    {
        //数据尚未接收完
        if (rxCount >= rxLen)
        {
            if ((rxCount - rxLen) < 20)
                return; //没有达到20个字节
        }
        else
        {
            if ((MAX_SIZE - rxLen + rxCount) < 20)
                return; //没有达到20个字节
        }
    }
    //达到了20个字节，或接收完成
    while (rxCount != rxLen) //有待取出数据
    {
        bleUartData[i] = rxBuf[rxLen];
        rxLen++;
        if (rxLen >= MAX_SIZE)
            rxLen = 0;
        i++;
        if (i >= 20)
            break; //数据长度超过20，只发送20个字节
    }

    if (atcmd_Compare_uart2atcmd(bleUartData, i) == 0)
    {
        //不是切换指令
        if (GetConnectedStatus())
        {
            SendNotifyData(bleUartData, i);
            Printf_OK();
        }
        else
        {
            //蓝牙未连接
            Printf_ConnectStatus(0);
        }
    }
}
/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : {u8} overflag-串口数据是否接收完成
 * Returns     : 
 * Date        : 2020-04-06 11:29:16
 * Description : 
 ******************************************************************************/
static void BleAtCmd(u8 overflag)
{
    u8 i = 0, j = rxLen;
    u8 bleUartData[AT_CMD_MAX] = {0};

    while (rxCount != j) //有待取出数据
    {
        bleUartData[i] = rxBuf[j];
        j++;
        if (j >= MAX_SIZE)
            j = 0;

        if ((bleUartData[i] == '\n') || (bleUartData[i] == '\r'))
        {
            //找到回车换行
            if ((rxBuf[j] == '\n') || (rxBuf[j] == '\r'))
            {
                //后一个字节也是回车换行符，移除
                j++;
                if (j >= MAX_SIZE)
                    j = 0;
            }
            rxLen = j;

            AtCmdParser(bleUartData, i);
            return; //退出该函数不再向下执行
        }

        i++;
        if (i >= AT_CMD_MAX)
        {
            rxLen = j; //指令太长,丢弃
            Printf_Error(ErrorCode_NotFound);
            return; //退出该函数不再向下执行
        }
    }

    //没有找到回车换行符
    if (overflag)
    {
        rxLen = j;
        AtCmdParser(bleUartData, i);
    }
}
/*******************************************************************************
 * Function    : Uart_Send_Data
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:02:59
 * Description : 串口数据发送判断
 ******************************************************************************/
void Uart_Send_Data(void)
{
    if ((txLen != txCount) && (txEn == 0))
    {
        //有数据待发送，发送使能标志未置1
        //Exit2Uart();
        txEn = 1;
        UART_ITConfig(UART1, UART_IT_TXIEN, ENABLE);
        UART_SendData(UART1, txBuf[txLen]);
    }
}
/*******************************************************************************
 * Function    : Uart_Receive_Data
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:01:52
 * Description : 接收数据
 ******************************************************************************/
void Uart_Receive_Data(void)
{
    if (rxLen == rxCount)
    {
        rxTimeOut = 0x00;
        return; //没有接收到数据
    }

    if (rxTimeOut < 0x02) //
    {
        //串口正在接受数据
        rxTimeOut++; //串口有数据时会一直清零
        if (getBleMode())
        {
            //AT指令模式，找到回车换行符
            BleAtCmd(0);
        }
        else
        {
            //透传模式，接收到的数据超过20个字节，取出数据
            BleSendData(0);
        }
    }
    else
    {
        //串口数据接收完成，取出数据
        if (getBleMode())
        {
            //AT指令模式，接收数据完成，取出数据
            BleAtCmd(1);
        }
        else
        {
            //透传模式
            BleSendData(1);
        }
        rxTimeOut = 0x00;
    }
}
/*******************************************************************************
 * Function    : Fun_Uart_Run
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-24 19:02:19
 * Description : 串口执行
 ******************************************************************************/
void Fun_Uart_Run(void)
{
    Uart_Send_Data();
    Uart_Receive_Data();
}
